package servidor;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import comum.CartaComum;
import comum.Cliente;
import comum.Jogador;
import comum.Mesa;
import comum.Servidor;
import java.util.HashSet;
import java.util.LinkedHashSet;
import javax.swing.JOptionPane;


public class SO_PresidenteServidor extends UnicastRemoteObject implements Servidor{	
    /**
     * 
     */
    private static final long serialVersionUID = 47022056632304002L;

    private static SO_PresidenteServidor INSTANCE;

    private List<Cliente> clientesConectados = new LinkedList<Cliente>();
    private HashMap<String, Cliente> nicknameClienteTable = new HashMap<String, Cliente>();

    private SO_PresidenteServidor() throws java.rmi.RemoteException{
        if (INSTANCE != null) {
            throw new IllegalStateException("Already Instantiated");
        }
    }

    public static SO_PresidenteServidor getServidor() {
        if (INSTANCE == null) {
            try {
                    INSTANCE = new SO_PresidenteServidor();
            } catch (Exception e) {
                    System.out.println("Trouble: "+ e);
            }
        }
        return INSTANCE;
    }

    public void iniciarServidor() {
        //System.err.println("A inicializacao do Servidor eh feita dentro da Main.");
        IU_Servidor.getIU_Servidor().exibirTela();
    }

    //Alterar o diagrama de sequencia VF2, Conectar Jogador
    public boolean conectarJogador(Cliente cliente, String nomeJogador) 
        
        
        throws java.rmi.RemoteException {	
        
        if (clientesConectados.contains(cliente)) return true;
        
        //Uma falha que notei agora eh:
        //um jogador tentar conectar usando o mesmo nome
        //de um outro jogador jah conectado 
        //Essa verificacao deve ser acrescentada ao
        //DIAGRAMA DE SEQUENCIA
        if(nicknameRepetido(nomeJogador)) return false;
                               
        if (RN_Partida.getRN_Partida().isSalaCheia()) {
            cliente.notificarErroDeConexao();
            return false;
        }
            
        //isso vai para o thread.
        //para cada servico assincrono, implementar class que extends Thread 
        clientesConectados.add(cliente);
        nicknameClienteTable.put(nomeJogador, cliente);
        RN_Partida.getRN_Partida().adicionarJogador(nomeJogador);
        /// fim do que vai para o thread
        
        HashSet<String> hs = new HashSet<String>();
        for(String str : getNicknameClienteTable().keySet()) hs.add(str);        
        for(Cliente cli : clientesConectados) cli.notificarEspera(hs);
        // e se o thread for muito rapido e retornar antes da espera ser enviada? :P
        return true;       	
    }

    public HashMap<String, Cliente> getNicknameClienteTable() {
        return nicknameClienteTable;
    }
    
    public void fazerJogada(HashSet<CartaComum> selecao) throws java.rmi.RemoteException {
            RN_Partida.getRN_Partida().fazerJogada(selecao);            
    }

//    public void notificarEspera(Jogador jogador) {
//        try {
//            nicknameClienteTable.get(jogador.getNome()).notificarEspera();
//        } catch (RemoteException e) {
//            e.printStackTrace();
//        }
//    }

    public void registrarMaoDeCartas(Jogador jogador, LinkedHashSet<CartaComum> mao) {
        try {
            Cliente c1 = nicknameClienteTable.get(jogador.getNome());
            c1.registrarMaoDeCartas(mao);
        } catch (RemoteException e) {
            e.printStackTrace();
        }	
    }

    public void desconectarJogadores() throws java.rmi.RemoteException {
            
        Thread t = new Thread(){            
            @Override
            public void run(){
                for (Cliente cliente : clientesConectados) {
                    try{                       
                        cliente.notificarDesconexao();
                    }catch(Exception e){}
                }
                clientesConectados = new LinkedList<Cliente>();
            }
        };
        t.start();
        //Cria uma nova lista de clientes zerada.
        //Eh desta maneira que "desconectamos" os jogadores
        
        nicknameClienteTable = new HashMap<String, Cliente>();
        RN_Partida.getRN_Partida().resetarPartida();
        
    }
    

    public void desconectarJogadoresAposFim() {
    	Thread t = new Thread(){
            @Override
            public void run(){ 
                for (Cliente cliente : clientesConectados) {
                     try {
                        cliente.notificarDesconexao();
                     } catch (RemoteException e) {}            
                 }
                clientesConectados = new LinkedList<Cliente>();
            }
        };
        t.start();
         
         nicknameClienteTable = new HashMap<String, Cliente>();
         RN_Partida.getRN_Partida().resetarPartida();

    }

    
    // mÃ©todo eliminado
//    public Set<String> getJogadoresParticipantes() throws java.rmi.RemoteException {
//        return nicknameClienteTable.keySet();
//    }

    public void iniciarPartida(Mesa mesa) {
              
        for (Cliente cliente : clientesConectados) {
            try {
                cliente.iniciarPartida(mesa);    
            } catch (RemoteException e) {
                    e.printStackTrace();
            }
        }
    }

    public void atualizarMesa(Mesa mesa) {
        for (Cliente cliente :clientesConectados) {
            try {
                    cliente.atualizarMesa(mesa);
            } catch (RemoteException e) {
                    e.printStackTrace();
            }
        }
    }

    public void terminarPartida(Mesa mesa, HashMap<String, Integer> ranking) {
            for (Cliente cliente : clientesConectados) {
            try {
                cliente.terminarPartida(mesa, ranking);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean nicknameRepetido(String nickname) {
    	
    	for (String nickExiste : nicknameClienteTable.keySet()) {
    		if (nickExiste.equals(nickname))
    			return true;
    	}
    	
       // for (Cliente cliente : clientesConectados) {
         //   if(nicknameClienteTable.get(cliente).equals(nickname))
           //     return true;
        //}
        return false;
    }
	
}
